package XML与JSON;

import org.junit.jupiter.api.Test;
import org.junit.platform.commons.util.StringUtils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;
import org.xml.sax.helpers.DefaultHandler;

import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.sax.SAXTransformerFactory;
import javax.xml.transform.sax.TransformerHandler;
import javax.xml.transform.stream.StreamResult;
import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
import java.util.List;

public class SaxCase {
    private static Logger logger = LoggerFactory.getLogger(SaxCase.class);

    /**
     * 解析xml
     * @throws Exception
     */
    @Test
    public void parse() throws Exception {
   	 System.out.println("\nparse----------");
        SAXParserFactory factory = SAXParserFactory.newInstance();
        SAXParser parser = factory.newSAXParser();
        SaxHandler handler = new SaxHandler();
        parser.parse(SaxCase.class.getResourceAsStream("student.xml"), handler);//类的包路径下的相对路径
        logger.info(handler.getStudents().toString());
    }

    /**
     * 生成xml
     * @throws Exception
     */
    @Test
    public void toXml() throws Exception {
   	 System.out.println("\ntoXML----------");
        //创建SAX转换工厂
        SAXTransformerFactory factory = (SAXTransformerFactory) SAXTransformerFactory.newInstance();
        TransformerHandler handler = factory.newTransformerHandler();

        //创建handler转换器
        Transformer transformer = handler.getTransformer();
        //换行
        transformer.setOutputProperty(OutputKeys.INDENT, "yes");
        transformer.setOutputProperty(OutputKeys.ENCODING, "utf-8");

        ByteArrayOutputStream out = new ByteArrayOutputStream();
        StreamResult streamResult = new StreamResult(out);
        handler.setResult(streamResult);

        AttributesImpl attributes = new AttributesImpl();
        //打开doc对象
        handler.startDocument();
        handler.startElement("http://www.w3.org/TR/html4/school/", "", "school:class", null);

        //第一个学生
        attributes.clear();
        attributes.addAttribute("", "", "rollno", "", "1");
        attributes.addAttribute("", "", "school:age", "", "10");
        handler.startElement("", "", "student", attributes);
        handler.startElement("", "", "school:firstname", null);
        handler.characters("cxx1".toCharArray(), 0, 4);
        handler.endElement("", "", "school:firstname");
        handler.startElement("", "", "lastname", null);
        handler.characters("Bob1".toCharArray(), 0, 4);
        handler.endElement("", "", "lastname");
        handler.startElement("", "", "nickname", null);
        handler.characters("stars1".toCharArray(), 0, 6);
        handler.endElement("", "", "nickname");
        handler.startElement("", "", "marks", null);
        handler.characters("85".toCharArray(), 0, 2);
        handler.endElement("", "", "marks");
        handler.endElement("", "", "student");
        //第二个学生
        attributes.clear();
        attributes.addAttribute("", "", "rollno", "", "2");
        handler.startElement("", "", "student", attributes);
        handler.startElement("", "", "firstname", null);
        handler.characters("cxx2".toCharArray(), 0, 4);
        handler.endElement("", "", "firstname");
        handler.startElement("", "", "lastname", null);
        handler.characters("Bob2".toCharArray(), 0, 4);
        handler.endElement("", "", "lastname");
        handler.startElement("", "", "nickname", null);
        handler.characters("stars2".toCharArray(), 0, 6);
        handler.endElement("", "", "nickname");
        handler.startElement("", "", "marks", null);
        handler.characters("85".toCharArray(), 0, 2);
        handler.endElement("", "", "marks");
        handler.endElement("", "", "student");
        //第三个学生
        attributes.clear();
        attributes.addAttribute("", "", "rollno", "", "3");
        handler.startElement("", "", "student", attributes);
        handler.startElement("", "", "firstname", null);
        handler.characters("cxx3".toCharArray(), 0, 4);
        handler.endElement("", "", "firstname");
        handler.startElement("", "", "lastname", null);
        handler.characters("Bob3".toCharArray(), 0, 4);
        handler.endElement("", "", "lastname");
        handler.startElement("", "", "nickname", null);
        handler.characters("stars3".toCharArray(), 0, 6);
        handler.endElement("", "", "nickname");
        handler.startElement("", "", "marks", null);
        handler.characters("85".toCharArray(), 0, 2);
        handler.endElement("", "", "marks");
        handler.endElement("", "", "student");

        handler.endElement("", "", "school:class");

        handler.endDocument();
        logger.info("\n"+out.toString());
    }
}

class SaxHandler extends DefaultHandler {
    private String text;
    private static Logger logger = LoggerFactory.getLogger(SaxHandler.class);

    private List<Student> students = new ArrayList<>();
    private Student student = null;

    public List<Student> getStudents() {
        return students;
    }

    public SaxHandler() {}

    @Override
    public void startDocument() throws SAXException {//解析开始时触发
        super.startDocument();
        logger.info("SAX解析开始");
    }

    @Override
    public void endDocument() throws SAXException {//解析结束时触发
        super.endDocument();
        logger.info("SAX解析结束");
    }

    @Override
    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
        super.startElement(uri, localName, qName, attributes);
        logger.info("qName={}", qName);
        if (qName.equals("student") || qName.equals("school:student")) {//处理开始元素的属性
            student = new Student();
            students.add(student);

				for (int i=0;i<attributes.getLength();i++) {
					System.out.println(attributes.getQName(i) + "=\"" + attributes.getValue(i) + "\"");
				}
				
            student.setRollno(Integer.parseInt(attributes.getValue("rollno")));
            String age = attributes.getValue("school:age");
            if (StringUtils.isNotBlank(age)) {
                student.setAge(Integer.parseInt(age));
            }
        }
    }

    @Override
    public void endElement(String uri, String localName, String qName) throws SAXException {
        super.endElement(uri, localName, qName);
        if ("firstname".equals(qName) || "school:firstname".equals(qName) ) {
            student.setFirstname(text);
        } else if ("lastname".equals(qName)) {
            student.setLastname(text);
        } else if ("nickname".equals(qName)) {
            student.setNickname(text);
        } else if ("marks".equals(qName)) {
            student.setMarks(text);
        }
    }

    @Override
    public void characters(char[] ch, int start, int length) throws SAXException {
        super.characters(ch, start, length);
        text = new String(ch, start, length);//遇见文本(text),也即元素的值(values),触发时的text保存在char[] ch中，起始点：start,文本长度：length
    }
}